/**
 * 事件管理系统（Cocos Creator 3.8）
 * 
 * 功能特性：
 * - ✅ 类型安全的事件订阅和发布
 * - ✅ 支持事件优先级
 * - ✅ 支持一次性监听（once）
 * - ✅ 支持异步事件处理
 * - ✅ 支持事件拦截和取消
 * - ✅ 自动内存管理（防止内存泄漏）
 * - ✅ 高性能设计
 * - ✅ 完整的事件生命周期
 * - ✅ 调试和统计功能
 * 
 * @author AI Assistant
 * @date 2025-11-30
 * @version 1.0.0
 */

import { Log } from '../logger/LoggerGlobal';

// ==================== 类型定义 ====================

/**
 * 事件处理函数
 */
export type EventHandler<T = any> = (data: T) => void | boolean | Promise<void | boolean>;

/**
 * 异步事件处理函数
 */
export type AsyncEventHandler<T = any> = (data: T) => Promise<void | boolean>;

/**
 * 事件监听器配置
 */
export interface EventListenerOptions {
    /** 优先级（数值越大优先级越高，默认 0） */
    priority?: number;
    /** 是否只触发一次（默认 false） */
    once?: boolean;
    /** 监听器目标对象（用于自动清理） */
    target?: any;
    /** 是否异步执行（默认 false） */
    async?: boolean;
}

/**
 * 事件监听器内部数据
 */
interface EventListener<T = any> {
    /** 事件处理函数 */
    handler: EventHandler<T>;
    /** 优先级 */
    priority: number;
    /** 是否只触发一次 */
    once: boolean;
    /** 目标对象 */
    target?: any;
    /** 是否异步 */
    async: boolean;
    /** 监听器 ID */
    id: number;
}

/**
 * 事件数据
 */
export interface EventData<T = any> {
    /** 事件类型 */
    type: string;
    /** 事件数据 */
    data: T;
    /** 时间戳 */
    timestamp: number;
    /** 是否已取消 */
    cancelled: boolean;
    /** 是否已停止传播 */
    stopped: boolean;
}

/**
 * 事件统计信息
 */
export interface EventStats {
    /** 事件类型 */
    type: string;
    /** 监听器数量 */
    listenerCount: number;
    /** 触发次数 */
    emitCount: number;
    /** 最后触发时间 */
    lastEmitTime: number;
    /** 平均处理时间（毫秒） */
    avgProcessTime: number;
}

// ==================== 事件管理器 ====================

/**
 * 事件管理器类
 * 
 * 使用示例：
 * ```typescript
 * // 创建全局事件管理器
 * const eventManager = EventManager.getInstance();
 * 
 * // 订阅事件
 * eventManager.on('playerDied', (data) => {
 *     console.log('玩家死亡:', data);
 * });
 * 
 * // 发布事件
 * eventManager.emit('playerDied', { playerId: 1, reason: 'monster' });
 * 
 * // 取消订阅
 * eventManager.off('playerDied', handler);
 * ```
 */
export class EventManager {
    /** 单例实例 */
    private static instance: EventManager | null = null;

    /** 事件监听器映射表 */
    private listeners: Map<string, EventListener[]> = new Map();

    /** 监听器 ID 计数器 */
    private listenerIdCounter: number = 0;

    /** 事件统计数据 */
    private stats: Map<string, EventStats> = new Map();

    /** 是否启用调试模式 */
    private debugMode: boolean = false;

    /** 是否启用统计 */
    private enableStats: boolean = false;

    /** 待清理的监听器（用于在事件触发过程中安全地移除监听器） */
    private pendingRemovals: Set<number> = new Set();

    /** 是否正在发送事件 */
    private emitting: boolean = false;

    /**
     * 私有构造函数（单例模式）
     */
    private constructor() {
        // 私有构造函数
    }

    /**
     * 获取单例实例
     */
    public static getInstance(): EventManager {
        if (!EventManager.instance) {
            EventManager.instance = new EventManager();
        }
        return EventManager.instance;
    }

    /**
     * 创建新的事件管理器实例（用于局部事件总线）
     */
    public static create(): EventManager {
        return new EventManager();
    }

    /**
     * 销毁单例实例
     */
    public static destroyInstance(): void {
        if (EventManager.instance) {
            EventManager.instance.clear();
            EventManager.instance = null;
        }
    }

    // ==================== 事件订阅 ====================

    /**
     * 订阅事件
     * 
     * @param type 事件类型
     * @param handler 事件处理函数
     * @param options 监听器配置
     * @returns 取消订阅函数
     * 
     * @example
     * ```typescript
     * const unsubscribe = eventManager.on('levelUp', (data) => {
     *     console.log('升级到', data.level);
     * }, { priority: 10 });
     * 
     * // 取消订阅
     * unsubscribe();
     * ```
     */
    public on<T = any>(
        type: string,
        handler: EventHandler<T>,
        options: EventListenerOptions = {}
    ): () => void {
        if (!type || typeof handler !== 'function') {
            Log.error('[EventManager] 无效的事件类型或处理函数');
            return () => {};
        }

        const listener: EventListener<T> = {
            handler,
            priority: options.priority ?? 0,
            once: options.once ?? false,
            target: options.target,
            async: options.async ?? false,
            id: ++this.listenerIdCounter
        };

        // 获取或创建监听器列表
        let listenerList = this.listeners.get(type);
        if (!listenerList) {
            listenerList = [];
            this.listeners.set(type, listenerList);
        }

        // 插入监听器（按优先级排序）
        this.insertListener(listenerList, listener);

        // 初始化统计数据
        if (this.enableStats && !this.stats.has(type)) {
            this.stats.set(type, {
                type,
                listenerCount: 0,
                emitCount: 0,
                lastEmitTime: 0,
                avgProcessTime: 0
            });
        }

        // 更新监听器数量
        if (this.enableStats) {
            const stat = this.stats.get(type)!;
            stat.listenerCount = listenerList.length;
        }

        if (this.debugMode) {
            Log.info(`[EventManager] 订阅事件: ${type}, 优先级: ${listener.priority}, 总监听器: ${listenerList.length}`);
        }

        // 返回取消订阅函数
        return () => this.offById(type, listener.id);
    }

    /**
     * 订阅一次性事件
     * 
     * @param type 事件类型
     * @param handler 事件处理函数
     * @param options 监听器配置
     * @returns 取消订阅函数
     * 
     * @example
     * ```typescript
     * eventManager.once('gameStart', () => {
     *     console.log('游戏开始！');
     * });
     * ```
     */
    public once<T = any>(
        type: string,
        handler: EventHandler<T>,
        options: EventListenerOptions = {}
    ): () => void {
        return this.on(type, handler, { ...options, once: true });
    }

    /**
     * 取消订阅事件
     * 
     * @param type 事件类型
     * @param handler 事件处理函数（如果不传，则移除该事件的所有监听器）
     * 
     * @example
     * ```typescript
     * eventManager.off('playerDied', handler);
     * eventManager.off('playerDied'); // 移除所有监听器
     * ```
     */
    public off<T = any>(type: string, handler?: EventHandler<T>): void {
        const listenerList = this.listeners.get(type);
        if (!listenerList) {
            return;
        }

        if (!handler) {
            // 移除该事件的所有监听器
            if (this.emitting) {
                // 如果正在发送事件，标记为待删除
                listenerList.forEach(listener => this.pendingRemovals.add(listener.id));
            } else {
                this.listeners.delete(type);
            }

            if (this.debugMode) {
                Log.info(`[EventManager] 移除事件所有监听器: ${type}`);
            }
        } else {
            // 移除特定的监听器
            const index = listenerList.findIndex(listener => listener.handler === handler);
            if (index !== -1) {
                const listener = listenerList[index];
                if (this.emitting) {
                    this.pendingRemovals.add(listener.id);
                } else {
                    listenerList.splice(index, 1);
                }

                if (this.debugMode) {
                    Log.info(`[EventManager] 移除事件监听器: ${type}`);
                }
            }
        }

        // 更新统计
        if (this.enableStats) {
            const stat = this.stats.get(type);
            if (stat) {
                stat.listenerCount = listenerList.length;
            }
        }
    }

    /**
     * 根据目标对象取消订阅
     * 
     * @param target 目标对象
     * 
     * @example
     * ```typescript
     * // 订阅时指定 target
     * eventManager.on('update', handler, { target: this });
     * 
     * // 组件销毁时自动清理
     * onDestroy() {
     *     eventManager.offByTarget(this);
     * }
     * ```
     */
    public offByTarget(target: any): void {
        if (!target) {
            return;
        }

        let removedCount = 0;
        this.listeners.forEach((listenerList, type) => {
            const toRemove: number[] = [];
            listenerList.forEach(listener => {
                if (listener.target === target) {
                    if (this.emitting) {
                        this.pendingRemovals.add(listener.id);
                    } else {
                        toRemove.push(listener.id);
                    }
                    removedCount++;
                }
            });

            if (!this.emitting) {
                toRemove.forEach(id => {
                    const index = listenerList.findIndex(l => l.id === id);
                    if (index !== -1) {
                        listenerList.splice(index, 1);
                    }
                });
            }
        });

        if (this.debugMode) {
            Log.info(`[EventManager] 根据目标移除 ${removedCount} 个监听器`);
        }
    }

    // ==================== 事件发布 ====================

    /**
     * 发布事件（同步）
     * 
     * @param type 事件类型
     * @param data 事件数据
     * @returns 事件是否被取消
     * 
     * @example
     * ```typescript
     * eventManager.emit('coinCollected', { amount: 100 });
     * ```
     */
    public emit<T = any>(type: string, data?: T): boolean {
        const listenerList = this.listeners.get(type);
        if (!listenerList || listenerList.length === 0) {
            if (this.debugMode) {
                Log.warn(`[EventManager] 事件无监听器: ${type}`);
            }
            return false;
        }

        // 创建事件数据
        const eventData: EventData<T> = {
            type,
            data: data as T,
            timestamp: Date.now(),
            cancelled: false,
            stopped: false
        };

        // 标记正在发送事件
        this.emitting = true;

        const startTime = this.enableStats ? performance.now() : 0;

        try {
            // 执行监听器（已按优先级排序）
            for (let i = 0; i < listenerList.length; i++) {
                const listener = listenerList[i];

                // 检查是否已被标记为删除
                if (this.pendingRemovals.has(listener.id)) {
                    continue;
                }

                try {
                    // 执行处理函数
                    const result = listener.handler(data as T);

                    // 处理返回值
                    if (result === false) {
                        eventData.cancelled = true;
                        if (this.debugMode) {
                            Log.info(`[EventManager] 事件被取消: ${type}`);
                        }
                        break;
                    }

                    // 如果是一次性监听器，标记为待删除
                    if (listener.once) {
                        this.pendingRemovals.add(listener.id);
                    }

                    // 检查是否停止传播
                    if (eventData.stopped) {
                        break;
                    }
                } catch (error) {
                    Log.error(`[EventManager] 事件处理出错 (${type}):`, error);
                }
            }

            // 更新统计
            if (this.enableStats) {
                const stat = this.stats.get(type);
                if (stat) {
                    stat.emitCount++;
                    stat.lastEmitTime = eventData.timestamp;
                    const processTime = performance.now() - startTime;
                    stat.avgProcessTime = (stat.avgProcessTime * (stat.emitCount - 1) + processTime) / stat.emitCount;
                }
            }

            if (this.debugMode) {
                Log.info(`[EventManager] 事件触发: ${type}, 监听器数: ${listenerList.length}, 耗时: ${(performance.now() - startTime).toFixed(2)}ms`);
            }

            return eventData.cancelled;
        } finally {
            // 取消标记
            this.emitting = false;

            // 清理待删除的监听器
            this.processPendingRemovals();
        }
    }

    /**
     * 发布异步事件
     * 
     * @param type 事件类型
     * @param data 事件数据
     * @returns Promise，在所有监听器执行完毕后 resolve
     * 
     * @example
     * ```typescript
     * await eventManager.emitAsync('dataLoaded', { items: [...] });
     * ```
     */
    public async emitAsync<T = any>(type: string, data?: T): Promise<boolean> {
        const listenerList = this.listeners.get(type);
        if (!listenerList || listenerList.length === 0) {
            return false;
        }

        const eventData: EventData<T> = {
            type,
            data: data as T,
            timestamp: Date.now(),
            cancelled: false,
            stopped: false
        };

        this.emitting = true;
        const startTime = this.enableStats ? performance.now() : 0;

        try {
            for (let i = 0; i < listenerList.length; i++) {
                const listener = listenerList[i];

                if (this.pendingRemovals.has(listener.id)) {
                    continue;
                }

                try {
                    const result = await listener.handler(data as T);

                    if (result === false) {
                        eventData.cancelled = true;
                        break;
                    }

                    if (listener.once) {
                        this.pendingRemovals.add(listener.id);
                    }

                    if (eventData.stopped) {
                        break;
                    }
                } catch (error) {
                    Log.error(`[EventManager] 异步事件处理出错 (${type}):`, error);
                }
            }

            if (this.enableStats) {
                const stat = this.stats.get(type);
                if (stat) {
                    stat.emitCount++;
                    stat.lastEmitTime = eventData.timestamp;
                    const processTime = performance.now() - startTime;
                    stat.avgProcessTime = (stat.avgProcessTime * (stat.emitCount - 1) + processTime) / stat.emitCount;
                }
            }

            return eventData.cancelled;
        } finally {
            this.emitting = false;
            this.processPendingRemovals();
        }
    }

    // ==================== 辅助方法 ====================

    /**
     * 插入监听器（按优先级排序）
     */
    private insertListener(list: EventListener[], listener: EventListener): void {
        let inserted = false;
        for (let i = 0; i < list.length; i++) {
            if (listener.priority > list[i].priority) {
                list.splice(i, 0, listener);
                inserted = true;
                break;
            }
        }
        if (!inserted) {
            list.push(listener);
        }
    }

    /**
     * 根据 ID 取消订阅
     */
    private offById(type: string, id: number): void {
        const listenerList = this.listeners.get(type);
        if (!listenerList) {
            return;
        }

        if (this.emitting) {
            this.pendingRemovals.add(id);
        } else {
            const index = listenerList.findIndex(listener => listener.id === id);
            if (index !== -1) {
                listenerList.splice(index, 1);
            }
        }
    }

    /**
     * 处理待删除的监听器
     */
    private processPendingRemovals(): void {
        if (this.pendingRemovals.size === 0) {
            return;
        }

        this.listeners.forEach((listenerList, type) => {
            const filtered = listenerList.filter(listener => !this.pendingRemovals.has(listener.id));
            if (filtered.length !== listenerList.length) {
                if (filtered.length === 0) {
                    this.listeners.delete(type);
                } else {
                    this.listeners.set(type, filtered);
                }
            }
        });

        this.pendingRemovals.clear();
    }

    // ==================== 工具方法 ====================

    /**
     * 检查是否有监听器
     */
    public hasListener(type: string): boolean {
        const listenerList = this.listeners.get(type);
        return listenerList !== undefined && listenerList.length > 0;
    }

    /**
     * 获取监听器数量
     */
    public getListenerCount(type: string): number {
        const listenerList = this.listeners.get(type);
        return listenerList ? listenerList.length : 0;
    }

    /**
     * 获取所有事件类型
     */
    public getEventTypes(): string[] {
        return Array.from(this.listeners.keys());
    }

    /**
     * 清空所有事件监听器
     */
    public clear(): void {
        this.listeners.clear();
        this.stats.clear();
        this.pendingRemovals.clear();

        if (this.debugMode) {
            Log.info('[EventManager] 清空所有事件监听器');
        }
    }

    // ==================== 调试和统计 ====================

    /**
     * 启用调试模式
     */
    public setDebugMode(enabled: boolean): void {
        this.debugMode = enabled;
    }

    /**
     * 启用统计
     */
    public setStatsEnabled(enabled: boolean): void {
        this.enableStats = enabled;
        if (!enabled) {
            this.stats.clear();
        }
    }

    /**
     * 获取事件统计信息
     */
    public getStats(type?: string): EventStats | EventStats[] | null {
        if (!this.enableStats) {
            Log.warn('[EventManager] 统计功能未启用');
            return null;
        }

        if (type) {
            return this.stats.get(type) || null;
        }

        return Array.from(this.stats.values());
    }

    /**
     * 打印事件统计
     */
    public printStats(): void {
        if (!this.enableStats) {
            Log.warn('[EventManager] 统计功能未启用');
            return;
        }

        console.log('========== 事件统计 ==========');
        this.stats.forEach((stat, type) => {
            console.log(`事件: ${type}`);
            console.log(`  监听器数: ${stat.listenerCount}`);
            console.log(`  触发次数: ${stat.emitCount}`);
            console.log(`  平均耗时: ${stat.avgProcessTime.toFixed(2)}ms`);
            console.log(`  最后触发: ${new Date(stat.lastEmitTime).toLocaleString()}`);
        });
        console.log('==============================');
    }

    /**
     * 打印所有监听器
     */
    public printListeners(): void {
        console.log('========== 事件监听器 ==========');
        this.listeners.forEach((listenerList, type) => {
            console.log(`事件: ${type} (${listenerList.length} 个监听器)`);
            listenerList.forEach((listener, index) => {
                console.log(`  [${index}] 优先级: ${listener.priority}, Once: ${listener.once}, Async: ${listener.async}`);
            });
        });
        console.log('================================');
    }
}

// ==================== 导出 ====================

/**
 * 全局事件管理器实例
 */
export const globalEventManager = EventManager.getInstance();

/**
 * 默认导出
 */
export default EventManager;

